﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using JobHunter.Model.Entity;
using RonCommon.Util;
using HtmlAgilityPack;

namespace JobHunter.Model.Service
{
	public class YellowpageEmployerDownloader
	{
		private const string _websiteUrl = "http://www.yellowpage.com.au";
		
		private const string _searchUrl = _websiteUrl + "/search/listings?clue={0}&locationClue={1}&x=0&y=0";

		private readonly MyDbContext _context = null;

		public string What { get; private set; }

		public string Where { get; private set; }

		public YellowpageEmployerDownloader(string what, string where)
		{
			What = what;
			Where = where;
			_context = new MyDbContext();
		}

		private string GetFirstUrl()
		{
			return string.Format(_searchUrl, What, Where);
		}


		private string GetNextUrl(HtmlDocument doc)
		{
			var nextNode = doc.DocumentNode.SelectSingleNode(".//a[@id='link-page-next']");
			return nextNode != null ? _websiteUrl + nextNode.Attributes["href"].Value : null;
		}

		private Employer CreateEmployer(HtmlNode node)
		{
			var employer = new Employer();

			var nameNode = node.SelectSingleNode(".//div[@class='listingName paragraph']/a[@*]");
			employer.SourceUrl = _websiteUrl + nameNode.Attributes["href"].Value;
			employer.Name = nameNode.SelectSingleNode("./span").InnerText;

			var goldNode = node.SelectSingleNode(".//div[contains(@class, 'listingInfoPanel')]");
			if (goldNode != null)
			{
				employer.Description = GetNodeValue(goldNode, ".//div[@class='textDesc paragraph']");
				employer.Address = GetNodeValue(goldNode, ".//span[@class='address']");
				employer.Phone = GetNodeValue(goldNode, ".//div[@class='preferredContact paragraph']/span[@preferredcontact]");
			}
			employer.WebSite = GetWebSiteFromNodeString(GetNodeValue(node, ".//ul[@class='primaryListingLinks']//a[@name='listing_website']", "href"));

			employer.CreatedOn = DateTime.Now;

			return employer;
		}

		private static string GetNodeValue(HtmlNode node, string xpath, string attributeName = null)
		{
			string ret = null;
			var subNode = node.SelectSingleNode(xpath);
			if (subNode != null)
			{
				if (string.IsNullOrWhiteSpace(attributeName))
				{
					ret = subNode.InnerText;
				}
				else
				{
					ret = subNode.Attributes[attributeName].Value;
				}
				ret = HttpUtility.HtmlDecode(ret);
			}
			return ret;
		}

		private Regex _regWebSite = new Regex("WebSite=http%3A%2F%2F(?<WebSite>.*?)&",
							RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
		private string GetWebSiteFromNodeString(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
				return null;
			var match = _regWebSite.Match(value);
			if (match.Success)
			{
				return match.Groups["WebSite"].Value;
			}
			return null;
		}

		public IList<Employer> Retrieve()
		{
			var employers = new List<Employer>();
			var url = GetFirstUrl();
			var doc = new HtmlDocument();
			do
			{
				string html = HttpHelper.Get(url);
				if (string.IsNullOrWhiteSpace(html))
					break;
				doc.LoadHtml(html);
				foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='listingInfoContainer']"))
				{
					var employer = CreateEmployer(node);

					if (employers.All(e => e.Name != employer.Name) && _context.Employers.All(e => e.Name != employer.Name))
					{
						employers.Add(employer);
					}
					else
					{
						Console.WriteLine(string.Format("Duplicated: {0}", employer.Name));
					}
				}
				url = GetNextUrl(doc);
			} while (url != null);
			return employers;
		}

		[Obsolete]
		public void SaveOrUpdateAll()
		{
			var url = GetFirstUrl();
			var doc = new HtmlDocument();
			do
			{
				doc.LoadHtml(HttpHelper.Get(url));
				foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='listingInfoContainer']"))
				{
					var employer = CreateEmployer(node);

					if (_context.Employers.Count(e => e.Name == employer.Name) <= 0)
					{
						_context.Employers.Add(employer);
						_context.SaveChanges();
					}
					else
					{
						Console.WriteLine(string.Format("Duplicated: {0}", employer.Name));
					}
				}
				url = GetNextUrl(doc);
			} while (url != null);
		}

		public int Count()
		{
			var doc = new HtmlDocument();
			doc.LoadHtml(HttpHelper.Get(GetFirstUrl()));

			return int.Parse(doc.DocumentNode.SelectSingleNode("//span[@id='headerResults']/strong").InnerText);
		}
	}
}
